import { TaskList, Project } from '../domain/index';
import * as _ from 'lodash';
import { createSelector } from '@ngrx/store';
import { TaskListActionTypes, TaskListActions } from '../actions/task-list.action';
import { ProjectActionTypes, ProjectActions } from '../actions/projects.action';

export interface State {
    ids: string[];
    entities: { [id: string]: TaskList };
    selectedIds: string[];
}

const initialState: State = {
    ids: [],
    entities: {},
    selectedIds: []
};

const addTaskList = (state, action) => {
    const taskList = action.payload;
    // 如果存在该taskList 则不添加
    if (state.entities[taskList.id]) {
        return state;
    }
    // 如果不存在 则在 ids 中添加 taskList.id
    const ids = [...state.ids, taskList.id];
    // 在entities 中添加项目
    const entities = { ...state.entities, [taskList.id]: taskList };
    const newSelectedIds = [...state.selectedIds, taskList.id];
    return { ids: ids, entities, selectedIds: newSelectedIds };
};

const updateTaskList = (state, action) => {
    const taskList = action.payload;
    // 替换
    const entities = { ...state, [taskList.id]: taskList };
    return { ...state, entities };
};
const delTaskList = (state, action) => {
    const taskList = action.payload;
    console.log('a', state.ids);
    const newIds = state.ids.filter(id => id !== taskList.id);
    const stateEntities = state.entities;
    const newEntities = newIds.reduce((entities, id: string) => ({ ...entities, [id]: stateEntities[id] }), {});
    const newSelectedIds = state.selectedIds.filter(id => id !== taskList.id);
    return { ids: newIds, entities: newEntities, selectedIds: newSelectedIds };
};
// 加载新数据， 如果存在则不添加，如果不存在则添加进去，方便进行分页
const loadTaskList = (state, action) => {
    const taskLists = action.payload; // 这里返回的是个数组
    const inComingIds = taskLists.map(p => p.id); // 获取传进来的所有id
    const newIds = _.difference(inComingIds, state.ids); // 获取两个数组的超集
    // 获取一个新的字典(对象) keyBy: 列表对象中的id 最为新对象的key 对象为值
    const inComingEntities = _.chain(taskLists).keyBy('id').mapValues(o => o).value();
    const newEntities = newIds.reduce((entities, id: string) => ({ ...entities, [id]: inComingEntities[id] }), {});
    return {
        ...state,
        ids: [...state.ids, ...newIds],
        entities: { ...state.entities, ...newEntities }
    };
};

// 交换列表
const swapTaskList = (state, action) => {
    const taskLists = <TaskList[]>action.payload;
    const updatedEntities = _.chain(taskLists)
        .keyBy('id')
        .mapValues(o => o)
        .value();
    const newEntities = { ...state, ...updatedEntities };
    return {
        ...state,
        entities: newEntities
    };
};

const selectProject = (state, action) => {
    const selected = <Project>action.payload;
    const selectedIds = state.ids.filter(id => state.entities[id].projectId === selected.id);
    return {
        ...state,
        selectedIds: selectedIds
    };
};

const delListsByPrj = (state, action) => {
    const project = <Project>action.payload;
    const taskListIds = project.taskLists;
    const remainingIds = _.difference(state.ids, taskListIds);
    const newEntities = remainingIds.reduce((entities, id) => ({ ...entities, [id]: state.entities[id] }), {});
    return {
        ids: [...remainingIds],
        entities: newEntities,
        selectedIds: []
    };
};

export function reducer(state = initialState, action: TaskListActions | ProjectActions): State {
    switch (action.type) {
        case TaskListActionTypes.ADD_SUCCESS: {
            return addTaskList(state, action);
        }
        case TaskListActionTypes.DELETE_SUCCESS: {
            return delTaskList(state, action);
        }
        case TaskListActionTypes.UPDATE_SUCCESS: {
            return updateTaskList(state, action);
        }
        case TaskListActionTypes.LOAD_SUCCESS: {
            return loadTaskList(state, action);
        }
        case TaskListActionTypes.SWAP_SUCCESS: {
            return swapTaskList(state, action);
        }
        case ProjectActionTypes.SELECT_PROJECT: {
            return selectProject(state, action);
        }
        case ProjectActionTypes.DELETE_SUCCESS: {
            return delListsByPrj(state, action);
        }
        default: {
            return state;
        }
    }
}

export const getIds = (state: State) => state.ids;
export const getEntities = (state: State) => state.entities;
export const getSelectedIds = (state: State) => state.selectedIds;
export const getSelected = createSelector(getIds, getEntities, (ids, entities) => {
    return ids.map(key => entities[key]);
});
